﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using PeoplesJukebox.Core.Interfaces;
using PeoplesJukebox.Core.Catalogues.Bases;
using System.IO;
using PeoplesJukebox.Core.Configuration;
using PeoplesJukebox.Core.Enums;
using PeoplesJukebox.Core.MediaItems;
using PeoplesJukebox.Core.Logging;

namespace PeoplesJukebox.Core.Catalogues
{
    /// <summary>
    /// Basic media catalogue using the file system as its source
    /// </summary>
    /// <remarks>
    /// Expects a file structure of x:\Root\Artist\Album\Track.xyz
    /// </remarks>
    public class FileSystemCatalogue : CatalogueBase
    {
        #region Private instance fields

        private int _maxTrackId;
        private Random _random = new Random();

        #endregion

        #region Constructors

        /// <summary>
        /// Default constructor
        /// </summary>
        public FileSystemCatalogue() : base() { }

        #endregion

        #region Overridden methods

        /// <summary>
        /// Loads the catalogue from the file system
        /// </summary>
        protected override void LoadItems()
        {
            //reset item list:
            int artistId = 0;
            int albumId = 0;
            int trackId = 0;
            this.AllItems.Clear();
            //and reload:
            string rootDirectory = FileSystemCatalogueConfiguration.Current.RootDirectory;
            if (rootDirectory.Replace(" ", string.Empty).ToLower() == Constants.MyMusic)
            {
                rootDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyMusic);
            }
            if (!Directory.Exists(rootDirectory))
            {
                Log.Error("Unable to load catalogue. Specified root directory not found: {0}", rootDirectory);
            }
            else
            {
                string extensions = FileSystemCatalogueConfiguration.Current.FileExtensions;
                Action<DirectoryInfo, List<FileInfo>> trackLoader = GetTrackLoader(extensions);
                Log.Info("Loading catalogue. Root directory: {0}, file extensions: {1}", rootDirectory, extensions);
                DirectoryInfo root = new DirectoryInfo(rootDirectory);
                foreach (DirectoryInfo artist in root.GetDirectories())
                {
                    this.AddItem(artistId, -1, artist.Name, string.Empty, string.Empty, artist.FullName, MediaItemType.Artist);
                    foreach (DirectoryInfo album in artist.GetDirectories())
                    {
                        this.AddItem(albumId, artistId, album.Name, string.Empty, artist.Name, album.FullName, MediaItemType.Album);
                        List<FileInfo> tracks = new List<FileInfo>();
                        trackLoader.Invoke(album, tracks);
                        foreach (FileInfo track in tracks)
                        {
                            this.AddItem(trackId++, albumId, GetTrackName(track.Name), album.Name, artist.Name, track.FullName, MediaItemType.Track);
                        }
                        albumId++;
                    }
                    artistId++;
                }
                //store the highest track id for use in Random:
                this._maxTrackId = trackId;
            }
        }

        /// <summary>
        /// Returns a random track ID, between 1 and the maximum loaded track
        /// </summary>
        /// <returns>Random track ID</returns>
        protected override int GetRandomTrackId()
        {
            return this._random.Next(this._maxTrackId);
        }

        #endregion

        #region Private instance methods

        private string GetTrackName(string filename)
        {
            string trackName = Path.GetFileNameWithoutExtension(filename);
            //if the name is prefixed with xx_, xx. etc remove
            //TODO - move this to a regex in config
            if (filename.Substring(2, 1) == "_")
            {
                trackName = trackName.Substring(3);
            }
            else if (filename.Substring(2, 2) == ". ")
            {
                trackName = trackName.Substring(4);
            }
            return trackName;
        }

        private Action<DirectoryInfo, List<FileInfo>> GetTrackLoader(string extensions)
        {
            Action<DirectoryInfo, List<FileInfo>> trackLoader = null;
            if (extensions.IndexOf(',') > -1)
            {
                trackLoader = (album, tracks) =>
                {
                    foreach (string extension in FileSystemCatalogueConfiguration.Current.FileExtensions.Split(','))
                    {
                        tracks.AddRange(album.GetFiles(extension.Trim()));
                    }
                };
            }
            else
            {
                trackLoader = (album, tracks) =>
                            tracks.AddRange(album.GetFiles(extensions.Trim()));
            }
            return trackLoader;
        }

        #endregion

        #region Private structures

        private struct Constants
        {
            public const string MyMusic = "mymusic";
        }

        #endregion
    }
}
